package org.springblade.tms.module.transportorder.base;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.logging.log4j.util.Strings;
import org.springblade.common.utils.EnumUtils;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.system.feign.IDictBizClient;
import org.springblade.system.user.entity.User;
import org.springblade.system.user.feign.IUserSearchClient;
import org.springblade.tms.global.constant.DictCodeConstant;
import org.springblade.tms.global.enums.*;
import org.springblade.tms.global.exception.CommonException;
import org.springblade.tms.global.utils.RSAUtils;
import org.springblade.tms.module.car.entity.TMCar;
import org.springblade.tms.module.car.service.ICarService;
import org.springblade.tms.module.demandorder.entity.TMDemandOrder;
import org.springblade.tms.module.demandorder.service.IDemandOrderService;
import org.springblade.tms.module.demandorderitem.entity.TMDemandOrderItem;
import org.springblade.tms.module.demandorderitem.service.IDemandOrderItemService;
import org.springblade.tms.module.exceptionreason.entity.TMExceptionReason;
import org.springblade.tms.module.exceptionreason.service.IExceptionReasonService;
import org.springblade.tms.module.exceptionrecord.entity.TMExceptionRecord;
import org.springblade.tms.module.exceptionrecord.service.IExceptionRecordService;
import org.springblade.tms.module.exceptionrecord.vo.TMExceptionRecordVO;
import org.springblade.tms.module.exceptiontype.entity.TMExceptionType;
import org.springblade.tms.module.exceptiontype.service.IExceptionTypeService;
import org.springblade.tms.module.gps.base.GPSRequestService;
import org.springblade.tms.module.gps.dto.*;
import org.springblade.tms.module.sap.base.SapRequestService;
import org.springblade.tms.module.sap.dto.SapTransportOrderDTO;
import org.springblade.tms.module.sap.dto.SapTransportOrderItemDTO;
import org.springblade.tms.module.sap.dto.WaybillEventDTO;
import org.springblade.tms.module.signedinfo.dto.TMSignedInfoDTO;
import org.springblade.tms.module.signedinfo.entity.TMSignedInfo;
import org.springblade.tms.module.signedinfo.service.ISignedInfoService;
import org.springblade.tms.module.supercargoinfo.entity.TMSupercargoInfo;
import org.springblade.tms.module.supercargoinfo.service.ISupercargoInfoService;
import org.springblade.tms.module.transportlinepoint.dto.TMTransportLinePointDTO;
import org.springblade.tms.module.transportlinepoint.entity.TMTransportLinePoint;
import org.springblade.tms.module.transportlinepoint.service.ITransportLinePointService;
import org.springblade.tms.module.transportorder.dto.TMTransportOrderDTO;
import org.springblade.tms.module.transportorder.dto.TransportOrderDTO;
import org.springblade.tms.module.transportorder.dto.WaybillStatusChangeDto;
import org.springblade.tms.module.transportorder.entity.TMTransportOrder;
import org.springblade.tms.module.transportorder.service.ITransportOrderService;
import org.springblade.tms.module.transportorder.vo.TMTransportOrderVO;
import org.springblade.tms.module.transportorder.vo.TransportOrderVo;
import org.springblade.tms.module.transportorder.wrapper.TransportOrderWrapper;
import org.springblade.tms.module.transportorderitem.entity.TMTransportOrderItem;
import org.springblade.tms.module.transportorderitem.service.ITransportOrderItemService;
import org.springblade.tms.module.userinfo.base.DriverManagementService;
import org.springblade.tms.module.userinfo.entity.TMUserInfo;
import org.springblade.tms.module.userinfo.service.IUserInfoService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static org.springblade.common.constant.TenantConstant.DEFAULT_TENANT_ID;
import static org.springblade.tms.global.constant.GPSConSigName.CONSIG_NAME;
import static org.springblade.tms.global.enums.WaybillStatusEnum.*;

/**
 * @projectName: BladeX
 * @package: org.springblade.tms.module.transportorder.base
 * @className: TransportListService
 * @author: yr
 * @description: 运单服务
 * @date: 2022/3/18 14:05
 */
@Service
@Transactional
public class TransportListService {
	@Resource
	private ITransportOrderService transportOrderService;
	@Resource
	private ITransportOrderItemService transportOrderItemService;
	@Resource
	private DriverManagementService driverManagementService;
	@Resource
	private ITransportLinePointService transportLinePointService;
	@Resource
	private ISignedInfoService signedInfoService;
	@Resource
	private IExceptionRecordService exceptionRecordService;
	@Resource
	private SapRequestService sapRequestService;
	@Resource
	private IUserSearchClient userClient;
	@Resource
	private IExceptionTypeService exceptionTypeService;
	@Resource
	private IExceptionReasonService exceptionReasonService;
	@Resource
	private IDemandOrderItemService demandOrderItemService;
	@Resource
	private IDemandOrderService demandOrderService;
	@Resource
	private ICarService carService;
	@Resource
	private IUserInfoService userInfoService;
	@Resource
	private ISupercargoInfoService supercargoInfoService;
	@Resource
	private GPSRequestService gpsRequestService;
	@Resource
	private IDictBizClient dictClient;

	/**
	 * @param transportOrderDTO:
	 * @param query:
	 * @return R<IPage       <       TMTransportOrderVO>>
	 * @author yr
	 * @description 运单列表查询
	 * @date 2022/3/18 15:29
	 */
	public R<IPage<TMTransportOrderVO>> list(TransportOrderDTO transportOrderDTO, Query query) {
		String freightOrderTypes = transportOrderDTO.getFreightOrderTypes();
		List<String> strings = new ArrayList<>();
		if (Strings.isNotBlank(freightOrderTypes)) {
			strings = Func.toStrList(freightOrderTypes);
		}
		TMUserInfo tmUserInfo = driverManagementService.getTmUserInfo();
		LambdaQueryWrapper<TMTransportOrder> queryWrapper = Condition.getQueryWrapper(new TMTransportOrder()).lambda()
			.like(transportOrderDTO.getTransportNo() != null, TMTransportOrder::getTransportNo, transportOrderDTO.getTransportNo())
			.like(transportOrderDTO.getOrderNo() != null, TMTransportOrder::getOrderNo, transportOrderDTO.getOrderNo())
			.like(transportOrderDTO.getDeliverNo() != null, TMTransportOrder::getDeliverNo, transportOrderDTO.getDeliverNo())
			.like(transportOrderDTO.getCarrierName() != null, TMTransportOrder::getCarrierName, transportOrderDTO.getCarrierName())
			.like(transportOrderDTO.getDriverName() != null, TMTransportOrder::getDriverName, transportOrderDTO.getDriverName())
			.like(transportOrderDTO.getCarNo() != null, TMTransportOrder::getCarNo, transportOrderDTO.getCarNo())
			.like(transportOrderDTO.getTransportStatus() != null, TMTransportOrder::getTransportStatus, transportOrderDTO.getTransportStatus())
			.like(transportOrderDTO.getBindCarNo() != null, TMTransportOrder::getBindCarNo, transportOrderDTO.getBindCarNo())
			.in(Strings.isNotBlank(freightOrderTypes), TMTransportOrder::getOrderType, strings)
			.like(StringUtil.isNotBlank(transportOrderDTO.getCustomerName()), TMTransportOrder::getCustomerName, transportOrderDTO.getCustomerName())//客户名称
			.like(StringUtil.isNotBlank(transportOrderDTO.getContainerNo()), TMTransportOrder::getContainerNo, transportOrderDTO.getContainerNo())//罐箱号
			.gt(transportOrderDTO.getPlanGetGoodsDateStart() != null, TMTransportOrder::getPlanGetGoodsDateStart, transportOrderDTO.getPlanGetGoodsDateStart())
			.lt(transportOrderDTO.getPlanGetGoodsDateEnd() != null, TMTransportOrder::getPlanGetGoodsDateStart, transportOrderDTO.getPlanGetGoodsDateEnd())
			.gt(transportOrderDTO.getPlannedHarvestDateStart() != null, TMTransportOrder::getPlanGetGoodsDateEnd, transportOrderDTO.getPlannedHarvestDateStart())
			.lt(transportOrderDTO.getPlannedHarvestDateEnd() != null, TMTransportOrder::getPlanGetGoodsDateEnd, transportOrderDTO.getPlannedHarvestDateEnd());
		if (tmUserInfo != null && tmUserInfo.getUserType().equals(UserTypeEnum.CARRIER.getValue())) {
			BladeUser user = AuthUtil.getUser();
			queryWrapper = queryWrapper.eq(TMTransportOrder::getCarrierNo, tmUserInfo.getTmId()).or().eq(TMTransportOrder::getCreateUser, user.getUserId());
		}
		IPage<TMTransportOrder> page = transportOrderService.page(Condition.getPage(query), queryWrapper.orderByDesc(TMTransportOrder::getCreateTime, TMTransportOrder::getId));
		IPage<TMTransportOrderVO> pageVO = TransportOrderWrapper.build().pageVO(page);
		List<Long> ids = pageVO.getRecords().stream().map(TMTransportOrder::getId).collect(Collectors.toList());
		Map<Long, List<TMTransportOrderItem>> transportOrderItemMap = transportOrderItemService.lambdaQuery().in(!ids.isEmpty(), TMTransportOrderItem::getParentId, ids).list().stream().collect(Collectors.groupingBy(TMTransportOrderItem::getParentId));
		pageVO.getRecords().forEach(record -> {

			record.setSourceLocationStreet(new StringBuilder(record.getStartLocationArea())
				.append(record.getStartLocationCity()).append(record.getStartLocationStreet()).toString());
			record.setDestinationStreet(new StringBuilder(record.getTargetLocationArea())
				.append(record.getTargetLocationCity()).append(record.getTargetLocationStreet()).toString());
			transportOrderItemMap.get(record.getId()).forEach(item -> {
				record.setMaterialInformation(new StringBuilder(record.getMaterialInformation()).append(item.getMatDesc())
					.append("*").append(item.getNum().toString()).append("(")
					.append(item.getUnit()).append(")").toString());
			});
		});
		return R.data(pageVO);
	}

	/**
	 * @param id:
	 * @return R<TransportOrderVo>
	 * @author yr
	 * @description 运输单详情
	 * @date 2022/3/18 15:25
	 */
	public R<TransportOrderVo> detail(Long id) {
		TMTransportOrder transportOrder = transportOrderService.lambdaQuery().eq(TMTransportOrder::getId, id).one();
		if (Strings.isNotBlank(transportOrder.getTankType())) {
			transportOrder.setTankType(EnumUtils.getEnumByValue(TankTypeEnum.class, transportOrder.getTankType()).get().description());
		}
		List<TMTransportOrderItem> transportOrderItems = transportOrderItemService.lambdaQuery().eq(TMTransportOrderItem::getParentId, id).list();
		transportOrderItems.forEach(tmTransportOrderItem -> tmTransportOrderItem.setNum(tmTransportOrderItem.getNum().setScale(4, BigDecimal.ROUND_DOWN)));
		//日志数据封装
		List<TMTransportLinePoint> transportLinePoints = transportLinePointService.lambdaQuery().eq(TMTransportLinePoint::getParentId, id).list();
//		transportLinePoints.forEach(tmTransportLinePoint -> tmTransportLinePoint.setTransport(WaybillStatusEnum.getDescriptionByValue(tmTransportLinePoint.getTransport())));
		List<Long> userIds = transportLinePoints.stream().map(TMTransportLinePoint::getCreateUser).collect(Collectors.toList());
		List<TMTransportLinePointDTO> transportLinePointDTOS = BeanUtil.copy(transportLinePoints, TMTransportLinePointDTO.class);
		if (!userIds.isEmpty()) {
			String join = StringUtil.join(userIds, ",");
			R<List<User>> user = userClient.listByUser(join);
			Map<Long, String> userMap = user.getData().stream().collect(Collectors.toMap(User::getId, User::getName));
			transportLinePointDTOS.forEach(tmTransportLinePoint -> {
				tmTransportLinePoint.setOperator(userMap.get(tmTransportLinePoint.getCreateUser()));
				if (Strings.isBlank(tmTransportLinePoint.getOperator())) {
					tmTransportLinePoint.setOperator("gsp");
				}
			});
		}
		//签收信息数据
		TMSignedInfo tmSignedInfo = signedInfoService.lambdaQuery().eq(TMSignedInfo::getParentId, id).one();
		//异常记录数据封装
		List<TMExceptionRecord> exceptionRecords = exceptionRecordService.lambdaQuery().eq(TMExceptionRecord::getParentId, id).list();
		List<Long> userIds2 = exceptionRecords.stream().map(TMExceptionRecord::getCreateUser).collect(Collectors.toList());
		List<TMExceptionRecordVO> tmExceptionRecordVOS = BeanUtil.copy(exceptionRecords, TMExceptionRecordVO.class);
		if (!userIds2.isEmpty()) {
			String join2 = StringUtil.join(userIds2, ",");
			R<List<User>> user2 = userClient.listByUser(join2);
			Map<Long, String> userMap2 = user2.getData().stream().collect(Collectors.toMap(User::getId, User::getName));
			tmExceptionRecordVOS.forEach(tmExceptionRecordDTO -> tmExceptionRecordDTO.setOperator(userMap2.get(tmExceptionRecordDTO.getCreateUser())));
		}
		//封装异常类型
		List<Long> exceptionTypeIds = exceptionRecords.stream().map(TMExceptionRecord::getExceptionType).collect(Collectors.toList());
		List<TMExceptionType> tmExceptionTypes = exceptionTypeService.lambdaQuery().in(!exceptionTypeIds.isEmpty(), TMExceptionType::getId, exceptionTypeIds).list();
		Map<Long, String> exceptionTypeMap = tmExceptionTypes.stream().collect(Collectors.toMap(TMExceptionType::getId, TMExceptionType::getName));
		tmExceptionRecordVOS.forEach(tmExceptionRecordVO -> tmExceptionRecordVO.setExceptionClass(exceptionTypeMap.get(tmExceptionRecordVO.getExceptionType())));
		//封装异常原因
		List<Long> exceptionReasonList = exceptionRecords.stream().map(TMExceptionRecord::getExceptionTypeDesc).collect(Collectors.toList());
		List<TMExceptionReason> tmExceptionReasons = exceptionReasonService.lambdaQuery().in(!exceptionReasonList.isEmpty(), TMExceptionReason::getId, exceptionReasonList).list();
		Map<Long, String> exceptionReasonMap = tmExceptionReasons.stream().collect(Collectors.toMap(TMExceptionReason::getId, TMExceptionReason::getReasonDesc));
		tmExceptionRecordVOS.forEach(tmExceptionRecordVO -> tmExceptionRecordVO.setAbnormal(exceptionReasonMap.get(tmExceptionRecordVO.getExceptionTypeDesc())));
		//封装好数据添加到返回data
		TransportOrderVo transportOrderVo = new TransportOrderVo();
		transportOrderVo.setSignedInfo(tmSignedInfo);
		transportOrderVo.setTmTransportLinePoints(transportLinePointDTOS);
		transportOrderVo.setTransportOrder(transportOrder);
		transportOrderVo.setTransportOrderItems(transportOrderItems);
		transportOrderVo.setExceptionRecords(tmExceptionRecordVOS);
		return R.data(transportOrderVo);
	}

	/**
	 * @param waybillStatusChangeDto:
	 * @return R<Boolean>
	 * @author yr
	 * @description 运单状态变更
	 * @date 2022/3/18 16:06
	 */
	public R<Boolean> waybillStatusChange(WaybillStatusChangeDto waybillStatusChangeDto) {
		TMTransportOrder transportOrder = transportOrderService.lambdaQuery().eq(TMTransportOrder::getId, waybillStatusChangeDto.getId()).one();
		//通过操作判断变更状态后
		if (waybillStatusChangeDto.getOperating().equals(OperatingEnum.ARRIVE_AT_THE_PICK_UP_POINT.getDescription())) {
			logSave(waybillStatusChangeDto.getId(), OperatingEnum.ARRIVE_AT_THE_PICK_UP_POINT.getDescription());
			stateVerification(transportOrder.getTransportStatus(), WaybillStatusEnum.ORDER_RECEIVED);
			transportOrder.setTransportStatus(WaybillStatusEnum.LOADED.getValue());
			transportOrderService.updateById(transportOrder);
			pushTMForWaybill(transportOrder, EventCodeEnum.ARRIVE_AT_THE_PICK_UP_POINT.getValue());
			GpsSignDTO gpsSignDTO = new GpsSignDTO();
			gpsSignDTO.setConsigNo(transportOrder.getTransportNo());
			gpsSignDTO.setSignTime(LocalDateTime.now());
			gpsSignDTO.setSignStatus("1");
			List<TMTransportOrderItem> list = transportOrderItemService.lambdaQuery().eq(TMTransportOrderItem::getParentId, transportOrder.getId()).list();
			BigDecimal num = list.stream().map(TMTransportOrderItem::getNum).reduce(BigDecimal.ZERO, BigDecimal::add);
			gpsSignDTO.setSignWeight(num);
//			gpsRequestService.sign(gpsSignDTO);
		} else if (waybillStatusChangeDto.getOperating().equals(OperatingEnum.START_SHIPMENT.getDescription())) {
			if (transportOrder.getOrderType().equals(TorTypeEnum.ZFO4.getValue()) || transportOrder.getOrderType().equals(TorTypeEnum.ZFOA.getValue())
				|| transportOrder.getOrderType().equals(TorTypeEnum.ZFO5.getValue()) || transportOrder.getOrderType().equals(TorTypeEnum.ZFOB.getValue())) {
				logSave(waybillStatusChangeDto.getId(), OperatingEnum.START_SHIPMENT.getDescription());
				stateVerification(transportOrder.getTransportStatus(), WaybillStatusEnum.LOADED);
				transportOrder.setTransportStatus(WaybillStatusEnum.ARRIVE_AT_THE_TRANSFER_STATION.getValue());
				transportOrderService.updateById(transportOrder);
			} else {
				logSave(waybillStatusChangeDto.getId(), OperatingEnum.START_SHIPMENT.getDescription());
				stateVerification(transportOrder.getTransportStatus(), WaybillStatusEnum.LOADED);
				transportOrder.setTransportStatus(WaybillStatusEnum.SHIPPED.getValue());
				transportOrderService.updateById(transportOrder);
				pushTMForWaybill(transportOrder, EventCodeEnum.SHIPPED.getValue());
			}
		} else if (waybillStatusChangeDto.getOperating().equals(OperatingEnum.ARRIVE_AT_THE_TRANSFER_STATION.getDescription())) {
			logSave(waybillStatusChangeDto.getId(), OperatingEnum.ARRIVE_AT_THE_TRANSFER_STATION.getDescription());
			stateVerification(transportOrder.getTransportStatus(), WaybillStatusEnum.ARRIVE_AT_THE_TRANSFER_STATION);
			transportOrder.setTransportStatus(WaybillStatusEnum.SHIPPED.getValue());
			transportOrderService.updateById(transportOrder);
			pushTMForWaybill(transportOrder, EventCodeEnum.SHIPPED.getValue());
		} else if (waybillStatusChangeDto.getOperating().equals(OperatingEnum.DELIVERY.getDescription())) {
			logSave(waybillStatusChangeDto.getId(), OperatingEnum.DELIVERY.getDescription());
			stateVerification(transportOrder.getTransportStatus(), WaybillStatusEnum.SHIPPED);
			if (transportOrder.getOrderType().equals(TorTypeEnum.ZFO2.getValue()) || transportOrder.getOrderType().equals(TorTypeEnum.ZFO8.getValue())) {
				transportOrder.setTransportStatus(WaybillStatusEnum.COMPLETED.getValue());
				transportOrderService.updateById(transportOrder);
			} else {
				transportOrder.setTransportStatus(WaybillStatusEnum.ARRIVED.getValue());
				transportOrderService.updateById(transportOrder);
			}
			pushTMForWaybill(transportOrder, EventCodeEnum.DELIVERED.getValue());
		} else if (waybillStatusChangeDto.getOperating().equals(OperatingEnum.DISCHARGE.getDescription())) {
			logSave(waybillStatusChangeDto.getId(), OperatingEnum.DISCHARGE.getDescription());
			stateVerification(transportOrder.getTransportStatus(), WaybillStatusEnum.ARRIVED);
			transportOrder.setTransportStatus(WaybillStatusEnum.COMPLETED.getValue());
			transportOrderService.updateById(transportOrder);
//			gpsRequestService.waybillStatusChange(new GPSWaybillStatusChangeDTO(CONSIG_NAME, transportOrder.getTransportNo(), "1"));
			pushTMForWaybill(transportOrder, EventCodeEnum.UNLOADED.getValue());
//			whetherTheDemandOrderIsCompleted(transportOrder);
//			GpsSignDTO gpsSignDTO = new GpsSignDTO();
//			gpsSignDTO.setConsigNo(transportOrder.getTransportNo());
//			gpsSignDTO.setSignTime(LocalDateTime.now());
//			gpsSignDTO.setSignStatus("2");
//			List<TMTransportOrderItem> list = transportOrderItemService.lambdaQuery().eq(TMTransportOrderItem::getParentId, transportOrder.getId()).list();
//			BigDecimal num = list.stream().map(TMTransportOrderItem::getNum).reduce(BigDecimal.ZERO, BigDecimal::add);
//			gpsSignDTO.setSignWeight(num);
//			gpsRequestService.sign(gpsSignDTO);
		}
		return R.status(true);
	}

	//上报TM
	private void pushTMForWaybill(TMTransportOrder transportOrder, String value) {
		WaybillEventDTO waybillEventDTO = new WaybillEventDTO();
		BeanUtil.copyNonNull(transportOrder, waybillEventDTO);
		waybillEventDTO.setType(SapTransportActionEnum.TRANSPORT.value());
		waybillEventDTO.setEventCode(value);
		waybillEventDTO.setEventTime(LocalDateTime.now());
		waybillEventDTO.setTorId(transportOrder.getOrderNo());
		sapRequestService.pushTmForUpdateWaybill(waybillEventDTO);
	}

	//生成日志
	private void logSave(Long id, String status) {
		TMTransportLinePoint tmTransportLinePoint = new TMTransportLinePoint();
		tmTransportLinePoint.setParentId(id);
		tmTransportLinePoint.setTransport(status);
		tmTransportLinePoint.setCreateTime(new Date());
		transportLinePointService.save(tmTransportLinePoint);
	}

	//订单状态校验
	private void stateVerification(String status, WaybillStatusEnum arrived) {
		if (!status.equals(arrived.getValue())) {
			CommonException.throwCommonException("运单状态为" + WaybillStatusEnum.getDescriptionByValue(status) + "，无法变更为" + arrived.getDescription());
		}
	}

	/**
	 * @param signedInfoDTO:
	 * @return R<Boolean>
	 * @author yr
	 * @description 签收
	 * @date 2022/3/21 13:40
	 */
	public R<Boolean> signForReceipt(TMSignedInfoDTO signedInfoDTO) {
		logSave(signedInfoDTO.getParentId(), OperatingEnum.SIGN_FOR_RECEIPT.getDescription());
		signedInfoDTO.setSignDate(LocalDateTime.now());
		TMTransportOrder transportOrder = transportOrderService.lambdaQuery().eq(TMTransportOrder::getId, signedInfoDTO.getParentId()).one();
		stateVerification(transportOrder.getTransportStatus(), WaybillStatusEnum.ARRIVED);
		transportOrder.setTransportStatus(WaybillStatusEnum.COMPLETED.getValue());
		transportOrderService.updateById(transportOrder);
		boolean save = signedInfoService.save(signedInfoDTO);
		WaybillEventDTO waybillEventDTO = new WaybillEventDTO();
		BeanUtil.copyNonNull(transportOrder, waybillEventDTO);
		BeanUtil.copyNonNull(signedInfoDTO, waybillEventDTO);
		waybillEventDTO.setSignRemark(signedInfoDTO.getRemark());
		waybillEventDTO.setType(SapTransportActionEnum.TRANSPORT.value());
		waybillEventDTO.setEventCode(EventCodeEnum.COMPLETED.getValue());
		waybillEventDTO.setTorId(transportOrder.getOrderNoNew());
		sapRequestService.pushTmForUpdateWaybill(waybillEventDTO);
		whetherTheDemandOrderIsCompleted(transportOrder);
//		gpsRequestService.waybillStatusChange(new GPSWaybillStatusChangeDTO(CONSIG_NAME, transportOrder.getTransportNo(), "1"));
		GpsSignDTO gpsSignDTO = new GpsSignDTO();
		gpsSignDTO.setConsigNo(transportOrder.getTransportNo());
		gpsSignDTO.setSignTime(LocalDateTime.now());
		gpsSignDTO.setSignStatus("2");
		gpsSignDTO.setSignWeight(signedInfoDTO.getNum());
		gpsSignDTO.setSignImg(signedInfoDTO.getSignPic());
//		gpsRequestService.sign(gpsSignDTO);
		return R.status(save);
	}

	//判断需求单是否完成
	public void whetherTheDemandOrderIsCompleted(TMTransportOrder transportOrder) {
		List<TMTransportOrder> tmTransportOrders = transportOrderService.lambdaQuery().eq(TMTransportOrder::getDemandId, transportOrder.getDemandId())
			.ne(TMTransportOrder::getTransportStatus, WaybillStatusEnum.COMPLETED.getValue()).list();
		List<TMDemandOrderItem> tmDemandOrderItems = demandOrderItemService.lambdaQuery().eq(TMDemandOrderItem::getParentId, transportOrder.getDemandId()).list();
		BigDecimal num = tmDemandOrderItems.stream().map(TMDemandOrderItem::getNum).reduce(BigDecimal.ZERO, BigDecimal::add);
		if (num.doubleValue() == 0 && tmTransportOrders.isEmpty()) {
			TMDemandOrder tmDemandOrder = demandOrderService.getById(transportOrder.getDemandId());
			tmDemandOrder.setDemandStatus(DemandStatusEnum.FINISH.value());
			demandOrderService.updateById(tmDemandOrder);
		}
	}

	/**
	 * @param transportOrderDTO:
	 * @return R
	 * @author yr
	 * @description 修改运单
	 * @date 2022/4/21 14:02
	 */
	public R update(TMTransportOrderDTO transportOrderDTO) {
		TMTransportOrder tmTransportOrder = transportOrderService.getById(transportOrderDTO.getId());
		R<Long> r = new R<>();
		TMCar tmCar = carService.getById(transportOrderDTO.getCarId());
		transportOrderDTO.setCarNo(tmCar.getCarNo());
		TMUserInfo driver = userInfoService.getById(transportOrderDTO.getDriverId());
		TMSupercargoInfo supercargoInfo = supercargoInfoService.getById(transportOrderDTO.getSupercargoId());
		//判断是否只修改了罐箱号
		TMCar car = carService.lambdaQuery().eq(TMCar::getId, transportOrderDTO.getCarId()).one();
		TMTransportOrder transportOrder = transportOrderService.getById(transportOrderDTO.getId());
		if (transportOrder.getDriverId().equals(transportOrderDTO.getDriverId()) &&
			transportOrder.getCarNo().equals(car.getCarNo())) {
			if (transportOrder.getSupercargoId() != null && transportOrder.getSupercargoId().equals(transportOrderDTO.getSupercargoId())) {
				BeanUtil.copyNonNull(transportOrderDTO, transportOrder);
				toSap(transportOrder, driver, supercargoInfo);
				transportOrderService.updateById(transportOrder);
				return R.data(transportOrder.getId());
			}
		}
		BeanUtil.copyNonNull(transportOrderDTO, transportOrder);
		//修改运单
		if (supercargoInfo == null) {
			supercargoInfo = new TMSupercargoInfo();
		}
		//校验是否可以拼单
		List<TMTransportOrder> tmTransportOrders = transportOrderService.lambdaQuery()
			.eq(TMTransportOrder::getCarNo, car.getCarNo())
			.eq(transportOrderDTO.getBindCarNo() != null, TMTransportOrder::getBindCarNo, transportOrderDTO.getBindCarNo())
			.eq(TMTransportOrder::getDriverId, driver.getId())
			.eq(supercargoInfo.getId() != null, TMTransportOrder::getSupercargoId, supercargoInfo.getId())
			.and(queryWrapper -> queryWrapper
				.and(tmTransportOrderLambdaQueryWrapper -> tmTransportOrderLambdaQueryWrapper
					.eq(TMTransportOrder::getTransportStatus, SHIPPED.getValue())
					.eq(TMTransportOrder::getTransportStatus, ARRIVED.getValue()))
				.and(wrapper -> wrapper.ne(TMTransportOrder::getOrderType, TorTypeEnum.ZFO4.getValue())
					.or().ne(TMTransportOrder::getOrderType, TorTypeEnum.ZFOA.getValue()))
				.or(wrapper -> wrapper.eq(TMTransportOrder::getTransportStatus, ARRIVED.getValue())
				))
			.eq(TMTransportOrder::getAbnormalSpelling, WhetherEnum.no.getValue())
			.list();
		if (!tmTransportOrders.isEmpty()) {
			throw CommonException.throwCommonException("当前车辆正在使用！");
		} else {
			if (!transportOrderDTO.getWhetherToMakeASingle()) {
				List<TMTransportOrder> list = transportOrderService.lambdaQuery()
					.eq(TMTransportOrder::getCarNo, car.getCarNo())
					.eq(Strings.isNotBlank(transportOrderDTO.getBindCarNo()), TMTransportOrder::getBindCarNo, transportOrderDTO.getBindCarNo())
					.eq(TMTransportOrder::getDriverId, driver.getId())
					.eq(supercargoInfo.getId() != null, TMTransportOrder::getSupercargoId, supercargoInfo.getId())
					.and(wrapper -> wrapper.eq(TMTransportOrder::getTransportStatus, LOADED.getValue())
						.or().eq(TMTransportOrder::getTransportStatus, WaybillStatusEnum.ORDER_RECEIVED.getValue())
						.or().eq(TMTransportOrder::getAbnormalSpelling, WhetherEnum.yes.getValue()))
					.ne(TMTransportOrder::getTransportStatus, WaybillStatusEnum.ABOLISHED.getValue())
					.list();
				if (!list.isEmpty()) {
					r.setCode(206);
					r.setSuccess(true);
					r.setMsg("该车辆已使用，是否进行拼单!");
				}
				//验证车辆司机押运员是否正在使用
				//判断车辆
				List<TMTransportOrder> tmTransportOrders1 = transportOrderService.lambdaQuery()
					.eq(TMTransportOrder::getCarNo, car.getCarNo())
					.and(tmTransportOrderLambdaQueryWrapper -> tmTransportOrderLambdaQueryWrapper
						.ne(TMTransportOrder::getTransportStatus, WaybillStatusEnum.COMPLETED.getValue())
						.ne(r.getCode() != 206, TMTransportOrder::getTransportStatus, LOADED.getValue())
						.and(wrapper -> wrapper
							.or(orderType -> orderType.eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFO4.getValue())
								.or().eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFOA.getValue())
								.or().eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFOB.getValue())
								.or().eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFO5.getValue())
								.and(tmTransportOrderLambdaQueryWrapper1 -> tmTransportOrderLambdaQueryWrapper1
									.ne(TMTransportOrder::getTransportStatus, SHIPPED.getValue())
									.ne(TMTransportOrder::getTransportStatus, ARRIVED.getValue()))
							)))
					.eq(TMTransportOrder::getAbnormalSpelling, WhetherEnum.no.getValue())
					.ne(TMTransportOrder::getCarNo, tmTransportOrder.getCarNo())
					.ne(TMTransportOrder::getTransportStatus, WaybillStatusEnum.ABOLISHED.getValue())
					.list();
				//判断挂车
				List<TMTransportOrder> tmTransportOrders2 = transportOrderService.lambdaQuery()
					.eq(TMTransportOrder::getBindCarNo, transportOrderDTO.getBindCarNo())
					.and(tmTransportOrderLambdaQueryWrapper -> tmTransportOrderLambdaQueryWrapper
						.ne(TMTransportOrder::getTransportStatus, WaybillStatusEnum.COMPLETED.getValue())
						.ne(r.getCode() != 206, TMTransportOrder::getTransportStatus, LOADED.getValue())
						.and(wrapper -> wrapper
							.or(orderType -> orderType.eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFO4.getValue())
								.or().eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFOA.getValue())
								.or().eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFOB.getValue())
								.or().eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFO5.getValue())
								.and(tmTransportOrderLambdaQueryWrapper1 -> tmTransportOrderLambdaQueryWrapper1
									.ne(TMTransportOrder::getTransportStatus, SHIPPED.getValue())
									.ne(TMTransportOrder::getTransportStatus, ARRIVED.getValue()))
							)))
					.eq(TMTransportOrder::getAbnormalSpelling, WhetherEnum.no.getValue())
					.ne(TMTransportOrder::getBindCarNo, tmTransportOrder.getBindCarNo())
					.apply(Strings.isBlank(transportOrderDTO.getBindCarNo()), "1=2")
					.ne(TMTransportOrder::getTransportStatus, WaybillStatusEnum.ABOLISHED.getValue())
					.list();
				//判断司机
				List<TMTransportOrder> tmTransportOrders3 = transportOrderService.lambdaQuery()
					.eq(TMTransportOrder::getDriverId, driver.getId())
					.and(tmTransportOrderLambdaQueryWrapper -> tmTransportOrderLambdaQueryWrapper
						.ne(TMTransportOrder::getTransportStatus, WaybillStatusEnum.COMPLETED.getValue())
						.ne(r.getCode() != 206, TMTransportOrder::getTransportStatus, LOADED.getValue())
						.and(wrapper -> wrapper
							.or(orderType -> orderType.eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFO4.getValue())
								.or().eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFOA.getValue())
								.or().eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFOB.getValue())
								.or().eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFO5.getValue())
								.and(tmTransportOrderLambdaQueryWrapper1 -> tmTransportOrderLambdaQueryWrapper1
									.ne(TMTransportOrder::getTransportStatus, SHIPPED.getValue())
									.ne(TMTransportOrder::getTransportStatus, ARRIVED.getValue()))
							)))
					.eq(TMTransportOrder::getAbnormalSpelling, WhetherEnum.no.getValue())
					.ne(TMTransportOrder::getDriverId, tmTransportOrder.getDriverId())
					.ne(TMTransportOrder::getTransportStatus, WaybillStatusEnum.ABOLISHED.getValue())
					.list();
				//判断押运员
				List<TMTransportOrder> tmTransportOrders4 = transportOrderService.lambdaQuery()
					.eq(TMTransportOrder::getSupercargoId, supercargoInfo.getId())
					.and(tmTransportOrderLambdaQueryWrapper -> tmTransportOrderLambdaQueryWrapper
						.ne(TMTransportOrder::getTransportStatus, WaybillStatusEnum.COMPLETED.getValue())
						.ne(r.getCode() != 206, TMTransportOrder::getTransportStatus, LOADED.getValue())
						.and(wrapper -> wrapper
							.or(orderType -> orderType.eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFO4.getValue())
								.or().eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFOA.getValue())
								.or().eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFOB.getValue())
								.or().eq(TMTransportOrder::getOrderType, TorTypeEnum.ZFO5.getValue())
								.and(tmTransportOrderLambdaQueryWrapper1 -> tmTransportOrderLambdaQueryWrapper1
									.ne(TMTransportOrder::getTransportStatus, SHIPPED.getValue())
									.ne(TMTransportOrder::getTransportStatus, ARRIVED.getValue()))
							)))
					.apply(supercargoInfo.getId() == null, "1=2")
					.eq(TMTransportOrder::getAbnormalSpelling, WhetherEnum.no.getValue())
					.ne(TMTransportOrder::getSupercargoId, tmTransportOrder.getSupercargoId())
					.ne(TMTransportOrder::getTransportStatus, WaybillStatusEnum.ABOLISHED.getValue())
					.list();
				if (!tmTransportOrders1.isEmpty()) {
					throw CommonException.throwCommonException("当前车辆正在使用！");
				} else if (!tmTransportOrders2.isEmpty()) {
					throw CommonException.throwCommonException("当前挂车正在使用！");
				} else if (!tmTransportOrders3.isEmpty()) {
					throw CommonException.throwCommonException("当前司机正在使用！");
				} else if (!tmTransportOrders4.isEmpty()) {
					throw CommonException.throwCommonException("当前押运员正在使用！");
				}
			}
		}
		if (r.getCode() == 206) {
			return r;
		}
		//上报gps
		WaybillSynchronizationDTO waybillSynchronizationDTO = BeanUtil.copy(transportOrder, WaybillSynchronizationDTO.class);
		List<TMTransportOrderItem> orderItems = transportOrderItemService.lambdaQuery().eq(TMTransportOrderItem::getParentId, transportOrder.getId()).list();
		List<GentlyBillGoodsDTO> billGoodsDTOList = BeanUtil.copy(orderItems, GentlyBillGoodsDTO.class);
		waybillSynchronizationDTO.setGentlyBillGoods(billGoodsDTOList.get(0));
		GentlyBillVehicleDTO gentlyBillVehicleDTO = BeanUtil.copy(car, GentlyBillVehicleDTO.class);
		BeanUtil.copyNonNull(driver, gentlyBillVehicleDTO);
		gentlyBillVehicleDTO.setDeviceNo(car.getGpsEquipmentNumber());
		gentlyBillVehicleDTO.setDeviceType(car.getTransportGoodsType().equals(CargoTypeEnum.DANGEROUS_GOODS.getValue()) ? "1" : "2");
		waybillSynchronizationDTO.setGentlyBillVehicle(gentlyBillVehicleDTO);
//		gpsRequestService.waybillSynchronization(waybillSynchronizationDTO);
		transportOrder.setDriverName(driver.getName());
		transportOrder.setSupercargoName(supercargoInfo.getName());
		transportOrder.setLeadSealNumber(transportOrderDTO.getLeadSealNumber());
		transportOrderService.updateById(transportOrder);
		//上报sap
		toSap(transportOrder, driver, supercargoInfo);
		return R.data(transportOrderDTO.getId());
	}

	private void toSap(TMTransportOrder transportOrder, TMUserInfo driver, TMSupercargoInfo supercargoInfo) {
		List<TMTransportOrderItem> list = transportOrderItemService.lambdaQuery().eq(TMTransportOrderItem::getParentId, transportOrder.getId()).list();
		SapTransportOrderDTO sapTransportOrderDTO = SapTransportOrderDTO.builder().build();
		BeanUtil.copyNonNull(transportOrder, sapTransportOrderDTO);
		sapTransportOrderDTO.setDriverPhone(driver.getPhone());
		if (supercargoInfo != null) {
			sapTransportOrderDTO.setSupercargoPhone(supercargoInfo.getPhone());
			sapTransportOrderDTO.setIdCardNo(supercargoInfo.getIdCardNo());
		}
		sapTransportOrderDTO.setCertificateDriverNo(driver.getCertificateDriverNo());
		List<SapTransportOrderItemDTO> sapTransportOrderItemDTOS = new ArrayList<>();
		for (TMTransportOrderItem tmTransportOrderItem : list) {
			sapTransportOrderItemDTOS.add(BeanUtil.copy(tmTransportOrderItem, SapTransportOrderItemDTO.class));
		}
		sapTransportOrderDTO.setType(SapTransportActionEnum.TRANSPORT.value());
		sapTransportOrderDTO.setTransportNo(transportOrder.getTransportNo());
		sapTransportOrderDTO.setItem(sapTransportOrderItemDTOS);
		sapRequestService.pushTmForDemandExtraInfo(sapTransportOrderDTO);
	}


	/**
	 * @param consigNo:
	 * @return R<String>
	 * @author yr
	 * @description 查询运单轨迹URL
	 * @date 2022/5/13 18:07
	 */
	public R<String> queryTheTrackOfTheWaybill(String consigNo) {
		HashMap<String, String> url = new HashMap<>();
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		String appKey = dictClient.getValue(DictCodeConstant.THIRD_INTERFACE, DictCodeConstant.APP_KEY, DEFAULT_TENANT_ID).getData();
		url.put("consigNo", consigNo);
		url.put("time", format.format(new Date()));
		url.put("consigName", CONSIG_NAME);
		try {
			String privateKey = dictClient.getValue(DictCodeConstant.THIRD_INTERFACE, DictCodeConstant.PUBLIC_KEY, DEFAULT_TENANT_ID).getData();
			String sign = RSAUtils.encryptByPublicKey(JSONUtil.toJsonStr(url), privateKey);
			sign = URLEncoder.encode(sign);
			String trace = dictClient.getValue(DictCodeConstant.THIRD_INTERFACE, DictCodeConstant.TRACE, DEFAULT_TENANT_ID).getData();
			return R.data(trace + "appKey=" + appKey + "&" + "sign=" + sign);
		} catch (Exception e) {
			CommonException.throwCommonException("加密异常");
		}
		return R.status(true);
	}

	/**
	 * @param :
	 * @return R<String>
	 * @author yr
	 * @description 地址管理url
	 * @date 2022/5/17 9:58
	 */
	public R<String> addressManagement() {
		try {
			HashMap<String, String> url = new HashMap<>();
			String trace = dictClient.getValue(DictCodeConstant.THIRD_INTERFACE, DictCodeConstant.MANAGE, DEFAULT_TENANT_ID).getData();
			return gpsTransfer(trace);
		} catch (Exception e) {
			CommonException.throwCommonException("加密异常");
		}
		return R.status(true);
	}

	/**
	 * @param :
	 * @return R<String>
	 * @author yr
	 * @description 监控中心url生成
	 * @date 2022/6/2 15:51
	 */
	public R<String> monitoringCenter() {
		try {
			String monitor = dictClient.getValue(DictCodeConstant.THIRD_INTERFACE, DictCodeConstant.MONITOR, DEFAULT_TENANT_ID).getData();
			return gpsTransfer(monitor);
		} catch (Exception e) {
			CommonException.throwCommonException("加密异常");
		}
		return R.status(true);
	}

	/**
	 * @param :
	 * @return R<String>
	 * @author yr
	 * @description 电子路书url
	 * @date 2022/7/4 17:18
	 */
	public R<String> roadBook() {
		try {
			String monitor = dictClient.getValue(DictCodeConstant.THIRD_INTERFACE, DictCodeConstant.ROAD_BOOK, DEFAULT_TENANT_ID).getData();
			return gpsTransfer(monitor);
		} catch (Exception e) {
			CommonException.throwCommonException("加密异常");
		}
		return R.status(true);
	}


	//gps调用方法
	private R<String> gpsTransfer(String monitor) throws Exception {
		String appKey = dictClient.getValue(DictCodeConstant.THIRD_INTERFACE, DictCodeConstant.APP_KEY, DEFAULT_TENANT_ID).getData();
		String userTag = dictClient.getValue(DictCodeConstant.THIRD_INTERFACE, DictCodeConstant.USER_TAG, DEFAULT_TENANT_ID).getData();
		String privateKey = dictClient.getValue(DictCodeConstant.THIRD_INTERFACE, DictCodeConstant.PRIVATE_KEY, DEFAULT_TENANT_ID).getData();
		String s = appKey + "|" + userTag + "|" + System.currentTimeMillis();
		String sign = RSAUtils.ucEncryptByPrivateKey(new String(s.getBytes(StandardCharsets.UTF_8)), privateKey);
		sign = URLEncoder.encode(sign);
		return R.data(monitor + "appKey=" + appKey + "&" + "userTag=" + userTag + "&" + "sign=" + sign);
	}

	//修改签收信息
	public R<Boolean> signForReceiptUpdate(TMSignedInfoDTO signedInfoDTO) {
		logSave(signedInfoDTO.getParentId(), OperatingEnum.SIGN_FOR_RECEIPT.getDescription());
		TMTransportOrder transportOrder = transportOrderService.lambdaQuery().eq(TMTransportOrder::getId, signedInfoDTO.getParentId()).one();
		boolean save = signedInfoService.updateById(signedInfoDTO);
		WaybillEventDTO waybillEventDTO = new WaybillEventDTO();
		BeanUtil.copyNonNull(transportOrder, waybillEventDTO);
		BeanUtil.copyNonNull(signedInfoDTO, waybillEventDTO);
		waybillEventDTO.setSignRemark(signedInfoDTO.getRemark());
		waybillEventDTO.setType(SapTransportActionEnum.TRANSPORT.value());
		waybillEventDTO.setEventCode(EventCodeEnum.COMPLETED.getValue());
		waybillEventDTO.setTorId(transportOrder.getOrderNoNew());
		sapRequestService.pushTmForUpdateWaybill(waybillEventDTO);
		whetherTheDemandOrderIsCompleted(transportOrder);
		GpsSignDTO gpsSignDTO = new GpsSignDTO();
		gpsSignDTO.setConsigNo(transportOrder.getTransportNo());
		gpsSignDTO.setSignTime(LocalDateTime.now());
		gpsSignDTO.setSignStatus("2");
		gpsSignDTO.setSignWeight(signedInfoDTO.getNum());
		gpsSignDTO.setSignImg(signedInfoDTO.getSignPic());
		gpsRequestService.sign(gpsSignDTO);
		return R.status(save);
	}
}
